package andy.demo.xml;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.zip.GZIPInputStream;

import org.apache.tools.bzip2.CBZip2InputStream;
import org.apache.xerces.parsers.DOMParser;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * A parser for XML in native and compressed XML formats.<br>
 * 
 * Typical pattern of use:
 * <p>
 * <code>
 * XmlDomParser xp = new XmlDomParser("aaa.xml");<br>
 * xp.parse();<br>
 * </code>
 * 
 * @author wangdw
 * @param <T>
 * 
 */
public abstract class XmlDomParser<T> {

    public static class XmlException extends Exception{
        private static final long serialVersionUID = -8580812252067635844L;
        public XmlException(){
            super();
        }
        public XmlException(String msg){
            super(msg);
        }
    } 
    
    protected DOMParser domParser = new DOMParser();
    private String xmlFile = null;
    private BufferedReader xmlBufferedReader = null;

    public XmlDomParser(String fileName) {
        xmlFile = fileName;
    }

    public XmlDomParser(InputStream is) {
        xmlBufferedReader = new BufferedReader(new InputStreamReader(is));
    }

    /**
     * The main parse method.
     * 
     * @throws IOException
     * @throws SAXException
     * 
     * @throws Exception
     */
    public abstract T parse() throws SAXException, IOException, XmlException;

    /**
     * 
     * @return An InputSource created from xmlFile
     * @throws IOException 
     */
    protected InputSource getInputSource() throws IOException {
        BufferedReader br = null;

        if (this.xmlBufferedReader != null) {
            br = this.xmlBufferedReader;
        } else if (xmlFile.endsWith(".gz")) {
            br = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(xmlFile))));
        } else if (xmlFile.endsWith(".bz2")) {
            FileInputStream fis = new FileInputStream(xmlFile);
            byte[] ignoreBytes = new byte[2];
            fis.read(ignoreBytes); // "B", "Z" bytes from commandline tools
            br = new BufferedReader(new InputStreamReader(new CBZip2InputStream(fis)));
        } else {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(xmlFile)));
        }

        return new InputSource(br);
    }

}
